package ca.etsmtl.logti.log619.lab05.analyser;

import java.util.ArrayList;
import java.util.HashMap;

import ca.etsmtl.logti.log619.lab05.SpamType;

public class FilterResult {
	private HashMap<String,MessageResult> lst = new HashMap<String,MessageResult>();

	private static final int SPAM_THREASHOLD = 50; // Inclusive (50% and higher are considered spam messages);
	private static final int DISABLED_FILTER = -1; // If a filter returns this value, it's not counted in the analysis
	
	// result Analysis
	int spamCount = 0; // Number of spam found
	int falsePositives = 0; // Number of false positives
	int falseNegatives = 0; // Number of false negatives
	int spamNoInfo = 0; // Number of emails not having any spam information in the email file
	ArrayList<String> errors = new ArrayList<String>(); // Keeps a record of all the problematic files.
	ArrayList<String> spams = new ArrayList<String>(); // Keeps a record of all the spam files.

	private class MessageResult {
		public MessageResult(SpamType type)
		{
			this.type = type;
		}
		public HashMap<String, Byte> results = new HashMap<String, Byte>();
		public SpamType type;
	}

	public void addResult(String messagePath, String filterName, SpamType origInfo ,
			byte b) {
		if (!lst.containsKey(messagePath))
			lst.put(messagePath, new MessageResult(origInfo));
		
		lst.get(messagePath).results.put(filterName, b);
	}
	
	public int getNumOfEmails()
	{
		return lst.size();
	}
	
	public void analyse()
	{
		// Reset variables
		this.spamCount = 0;
		this.falsePositives = 0;
		this.falseNegatives = 0;
		this.spamNoInfo = 0;
		errors.clear();
		
		for(String key : lst.keySet())
		{
			MessageResult tmr = lst.get(key);
			String err = "";
			
			// Determine if this file is spam or not.
			int percentageMean = 0;
			int donTCountFilters = 0;
			for (String filter : tmr.results.keySet())
			{
				int value = (int) tmr.results.get(filter);
				if (value == DISABLED_FILTER)
				{
					donTCountFilters++;
					continue;
				}
				percentageMean += (int) tmr.results.get(filter);
				if (tmr.results.get(filter) >= SPAM_THREASHOLD )
					err += filter + " (" + tmr.results.get(filter) + "%) ";
			}
			int spamRate = percentageMean / (tmr.results.keySet().size() - donTCountFilters);
			
			if (spamRate >= SPAM_THREASHOLD)
			{
				spamCount++;
				this.spams.add(key);
			}
			if (tmr.type == SpamType.mmmm)
				spamNoInfo++;
			else
			{
				if (tmr.type == SpamType.ham && spamRate >= SPAM_THREASHOLD)
				{
					falsePositives++;
					errors.add(String.format("File : %1$s \n\tFalse positive due to : %2$s",key,err));
				}
				else if (tmr.type == SpamType.spam && spamRate < SPAM_THREASHOLD)
				{
					falseNegatives++;
					errors.add(String.format("File : %1$s \n\tfalse negative",key));
				}
			}
		}
	}

	public String getOutput() {
		analyse();
		StringBuilder build = new StringBuilder();
		build.append("Number of emails analysed :");
		build.append(lst.size());
		build.append("\nNumber of spam emails found :");
		build.append(spamCount);
		if (lst.size() != spamNoInfo) { // Do we have any supplementary information about these emails?
			build.append("\nNumber of emails correctly analysed :");
			build.append(lst.size() - spamNoInfo - (falseNegatives + falsePositives));
			build.append("\n\tfalse negatives :");
			build.append(falseNegatives);
			build.append("\n\tFalse positives :");
			build.append(falsePositives);
			

			// List files if needed
			build.append("\n--------------------\nIncorrectly analysed files are :\n");
			for (String s : errors)
			{
				build.append(s);
				build.append('\n');
			}
		}
		else
		{
			build.append("\nList of spam found :");
			for (String s: spams)
			{
				build.append("\n\t");
				build.append(s);
			}
		}

		return build.toString();
	}
}
